package titt.server.service.db;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import titt.key.KeyFactory;
import titt.key.TITTKey;
import titt.server.service.Service;
import titt.server.service.invoker.TITTInternalInvoker;

public class Dispatcher {

	private final Map<Service, TITTInternalInvoker> listeners = new HashMap<Service, TITTInternalInvoker>();
	private final Map<Service, TITTKey> eventKeys = new HashMap<Service, TITTKey>();

	private final String eventMethod;

	public Dispatcher(String eventMethod) {
		this.eventMethod = eventMethod;
	}

	public void dispatchEvent(final Service eventSource) {
		Set<Service> keys = new HashSet<Service>();
		
		synchronized (eventSource) {
			for(Service s : listeners.keySet())
				if(shouldDispatch(s, eventSource))
					keys.add(s);
		}
		
		for(Service s : keys)
			dispatchEvent(getInvoker(s), s, eventSource);
		
	}
	
	private synchronized TITTInternalInvoker getInvoker(Service s) {
		return listeners.get(s);
	}


	public void attachListener(Service s, TITTInternalInvoker inv) {
		String[][] regInterface = s.getRegistrationInterface();
		
		for(int i = 1; i < regInterface.length; i++) {	
			if(regInterface[i][1].equals(eventMethod)) {
				synchronized (this) {
					listeners.put(s, inv);
					eventKeys.put(s, createEventKey(s.getKey()));		
				}
				break;
			}
		}
	}
	
	public synchronized void removeListener(Service s) {
		listeners.remove(s);
		eventKeys.remove(s);
	}

	private void dispatchEvent(TITTInternalInvoker inv, Service s, Service eventSource) {
		try {
			inv.call(eventMethod, (Object)eventSource.getKey().getTokens());
		}
		catch(Exception e) {	
		}
	}

	private TITTKey createEventKey(TITTKey key) {
		if(!key.containsWildcard())
			key = KeyFactory.createKey(key.asKeyString() + "*");
		return key;
	}

	private synchronized boolean shouldDispatch(Service s, Service eventSource) {
		return eventKeys.get(s).equivalentTo(eventSource.getKey());
	}
}
